home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / Control Panel 0.9.4 / TC 5 / MyExtension.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-02  |  13.3 KB  |  368 lines  |  [TEXT/KAHL]

  1. /*
  2.     MyExtension.c
  3.     
  4.     Written by Ken Worley, 02/01/94, using Symantec Think C 6.0.1.
  5.     Copyright 1994.
  6.     AOL KNEworley
  7.     
  8.     Feel free to use this code in an extension of your own.  Please don't
  9.     publish or distribute this code without giving me proper credit.
  10.     
  11.     This extension is an example.  It shows how to use an extension to install
  12.     a trap patch and shows how to share data between an extension, a control
  13.     panel, and a trap patch.  You can use this as a basis for writing your own
  14.     extension/control panel combination (or just a plain extension).
  15.         
  16.     The method for sharing data between the extension and patch was adapted
  17.     from an extension called 'FlashInit.'  This was an example extension written
  18.     by Richard Harvey in April 1990.  Thanks Richard!!  The method involves
  19.     allocating a chunk of memory, then replacing a dummy reference in the patch
  20.     code with the actual address of the memory (our shared memory structure).
  21.     
  22.     We can't use that method with the control panel code because it gets written
  23.     back to disk, so we also store the address of the shared data in a resource
  24.     that the control panel can access when it is opened.
  25.     
  26.     This extension also incorporates 'ShowIconFamily' by Patrick C. Beard and
  27.     modified by James W. Walker.  This piece of code
  28.     is called to display the extension's icon at startup.  This
  29.     code was based on the original ShowInit by Paul Mercer, Darin Adler, Paul
  30.     Snively and Steve Capps.  These are the guys to blame for our startup icon
  31.     parades.  That piece of code (ShowIconFamily.c) is public domain.  I made
  32.     some modifications to it in order to use it without any global variables.
  33.     
  34.     This extension uses no global or static variables, so it's not necessary
  35.     to set up and restore A4.  All of our 'global' data is in the shared data
  36.     structure (in a locked block in the system heap).
  37.     
  38.     I've also included a 'sysz' resource in the resource file.  Pre-System 7
  39.     Macs will look at this resource when loading the extension and interpret the
  40.     number there as a request to expand the system heap by the specified number
  41.     of bytes.  The expanded space is not reserved for the extension, it is just
  42.     added to the system heap space.  System 7 expands and contracts the system
  43.     heap dynamically and so ignores the 'sysz' resource.  A template is also included
  44.     for easily modifying the sysz resource with ResEdit.
  45.     
  46.     We use what I call a 'preferences' resource to save some settings between
  47.     restarts.  For the most part, this same information is also held in memory
  48.     (in the shared data structure) while the computer is running so that the
  49.     patch code can access the settings.  The resource is normally accessed once
  50.     by the extension code, then accessed and possibly changed later by the control
  51.     panel code.
  52.     
  53.     This code sets a couple of the fields in the shared data structure which are
  54.     accessed and/or modified by other code later on.  The 'CPon' field is set to
  55.     true or false depending on whether or not the preferences resource indicates
  56.     the control panel was set to 'on' or 'off' when last closed.  The 'patched'
  57.     field is set to true if the trap patch was installed and false if it was not.
  58.     
  59.     About the only thing you'll ever need to modify in this file when writing
  60.     your own extension (unless you're making major changes) are some of the #defines.
  61.     
  62.         kTrapToPatch determines which trap the patch is installed for.
  63.         kParamBytes is the number of bytes passed on the stack as parameters for
  64.             the trap routine.  (This would be zero for a register based trap.)
  65.         kReturnBytes is the number of bytes reserved on the stack for the return
  66.             value.  (This would also be zero for a register based trap.)
  67.             
  68.         kTaskRsrcNo is the resource number of the patch code.
  69.         kTaskRsrcType is the resource type of the patch code ('task').
  70.         
  71.         kCDEVRsrcNo is the resource number of the control panel code.  You shouldn't
  72.             need to change this.
  73.             
  74.         kIconFamilyID is the resource number of the icon family our final file will
  75.             be using.  The number is used to send to ShowInit so our icon can be
  76.             shown in the startup icon parade.
  77.         
  78.         kXIconID is the resource number of the icon family to be used when there was
  79.             a problem when loading the extension.  This icon looks Xed out.
  80.         
  81.         kNoPatchIconID is the resource number of the icon family to be used when
  82.             the patch is not loaded (when the control panel is set to "off").
  83.         
  84.         kMemAddrType is the resource type of the resource used to hold the address of
  85.             the shared data structure.
  86.         kMemAddrID is the resource number of the above resource.
  87. */
  88.  
  89. /* trap patching defines */
  90.  
  91. #define        kTrapToPatch        _MenuSelect
  92. #define        kParamBytes            4        /* a Point-in global coordinates */
  93. #define        kReturnBytes        4        /* long int-hiword is menu id-loword is item# */
  94.  
  95. /* patch code defines */
  96.  
  97. #define        kTaskRsrcNo            128        /* the patch code's resource number */
  98. #define        kTaskRsrcType        'task'    /* the patch code's resource type */
  99.  
  100. /* other defines */
  101.  
  102. #define        kCDEVRsrcNo            -4064    /* rsrc no of cdev code (rsrc type 'cdev') */
  103.  
  104. /* The following three icons are the ones I defined for this example.  Modify them */
  105. /* for your purposes or come up with some on your own.  */
  106.  
  107. #define        kIconFamilyID        -4064    /* rsrc no of ICN# rsrc with our icons */
  108. #define        kXIconID            -4033    /* rsrc no of Xed out icon family */
  109. #define        kNoPatchIconID        -4034    /* rsrc no of icon family when patch not inst. */
  110.  
  111. /* control panel preferences resource defines */
  112.  
  113. #define kCPprefsRsrcType    'pref'
  114. #define    kCPprefsRsrcID        -4048    /* careful - this number is also used in the cdev */
  115.  
  116. /* shared memory address resource defines */
  117.  
  118. #define kMemAddrType        'memA'
  119. #define kMemAddrID            -4048    /* careful - this number is also used in the cdev */
  120.  
  121. typedef struct {
  122.     long    theAddr;
  123. } **memAddrHdl;
  124.  
  125. #include    <Traps.h>
  126.  
  127. #include "SharedData.h"            /* The definition of our shared data structure. */
  128.                                 /* Includes definitions of myDataStruct, myDataPtr, */
  129.                                 /* and myDataHandle to refer to this data */
  130.  
  131. /* Prototypes */
  132.  
  133. void    main( void );
  134. void    ShowIconFamily(short iconId);
  135.  
  136. /* Functions */
  137.  
  138. void    main( void )
  139. {
  140.     myDataPtr            myData;        /* pointer to shared data structure */
  141.     Handle                myTask;        /* handle to my trap patch code */
  142.     memAddrHdl            addrHandle;    /* handle to memory address resource */
  143.     long                myTaskAddr;    /* used to get direct addr of task code */
  144.     THz                    saveZone;    /* used to save memory zone */
  145.     long                toReplace,    /* these two items are used to replace the bogus */
  146.                         replaceWith;    /* addr in the task and cdev code with the */
  147.                                         /* addr of the shared data structure */
  148.                                         
  149.     CPprefsHandle        prefsHandle;    /* Handle to the Control Panels prefs rsrc */
  150.     Boolean                showStartupIcon;    /* show icon at startup? */
  151.     Boolean                installPatch;        /* install trap patch? */
  152.     
  153.     Boolean                stillOK;        /* still OK to proceed? */
  154.     Boolean                sharedDataOK;    /* was shared data struct allocated OK? */
  155.     
  156.     stillOK = true;
  157.     showStartupIcon = true;
  158.     installPatch = true;
  159.     
  160.     myData = NULL;
  161.     myTask = NULL;
  162.     addrHandle = NULL;
  163.                                         
  164.     /*    First save the current memory zone, then switch to the System zone so
  165.      *    that all memory allocation occurs in the System Heap.
  166.      */
  167.     
  168.         saveZone = GetZone();
  169.         SetZone( SystemZone() );
  170.         
  171.     /*    Allocate memory (a pointer) for our data structure so that both this code
  172.      *    and the patch code will have access to the data.  (We'll see about
  173.      *    giving access to this data to the patch code later.)  We use a pointer
  174.      *    rather than a handle because the data has to be locked down anyway.
  175.      */
  176.         
  177.         myData = (myDataPtr)NewPtrSysClear(sizeof(myDataStruct));
  178.         
  179.         sharedDataOK = true;
  180.         
  181.         if ( !myData )
  182.         {
  183.             stillOK = false;
  184.             sharedDataOK = false;
  185.         }
  186.     
  187.     /*    Mark the data as in use until we're through with it.  Since we just
  188.      *    created it, we know no one is using it now.  Also initialize some
  189.      *    values in the shared data structure.
  190.      */
  191.         if ( sharedDataOK )
  192.         {
  193.             myData->inUse = true;
  194.             myData->oldTrap = 0L;
  195.             myData->CPprefsRsrc = NULL;
  196.         }
  197.  
  198.     /*    Load the control panel's preferences resource to see if we should show
  199.      *    the icon at startup and if we should patch the trap.  After we've read it,
  200.      *    release it.  The control panel will reload it.  If we cannot read the
  201.      *    resource from the file (probably because it doesn't yet exist), just assume
  202.      *    true/yes for both questions.
  203.      */
  204.      
  205.          myData->CPon = true;        /* preset to 'on' unless we find otherwise */
  206.                                      /* installPatch was also preset to true above */
  207.          
  208.          prefsHandle = (CPprefsHandle)Get1Resource( kCPprefsRsrcType, kCPprefsRsrcID );
  209.          if ( prefsHandle )
  210.          {
  211.              if ( !(*prefsHandle)->On )
  212.              {
  213.                  installPatch = false;
  214.                  myData->CPon = false;
  215.              }
  216.              
  217.              if ( !(*prefsHandle)->ShowIcon )
  218.                  showStartupIcon = false;
  219.                  
  220.              ReleaseResource( (Handle)prefsHandle );
  221.          }
  222.     
  223.     /*    Get the address of the trap we're going to patch. */
  224.         if ( sharedDataOK )
  225.             myData->oldTrap = NGetTrapAddress( kTrapToPatch, ToolTrap );
  226.     
  227.     /*    Put the size of the trap's parameters and the size of the return value
  228.      *    (can be zero) in the shared data structure so that the patch code has
  229.      *    access to it.  This is used by the patch code to handle parameters that
  230.      *    are passed on the stack (same for the return value).  Note that with
  231.      *    register based routines (like a lot of the memory routines), the patch
  232.      *    has to know which registers are used and what their sizes are itself.
  233.      *    With stack based routines, the patch does not necessarily need to know
  234.      *    anything else about the parameters unless it wants to do something with
  235.      *    them.
  236.      */
  237.          if ( sharedDataOK )
  238.          {
  239.              myData->paramBytes = kParamBytes;
  240.              myData->returnBytes = kReturnBytes;
  241.          }
  242.         
  243.     /*    Now load the code resource that comprises the actual 'patch.'  This code
  244.      *    will execute (instead of the original code) when the trap is executed.
  245.      *    The patch itself determines whether or not to execute (jump to) the original
  246.      *    trap code once it's done its thing.  The actual patch code is in its own
  247.      *    resource of type 'task'.
  248.      */
  249.          if ( installPatch && stillOK )
  250.          {
  251.             myTask = Get1Resource( kTaskRsrcType, kTaskRsrcNo );
  252.         
  253.             if ( !myTask )
  254.                 stillOK = false;
  255.         }
  256.         
  257.     /*    Here's an example of a clever technique used in Harvey's code.  We use the
  258.      *    Munger routine to replace a predetermined pattern in the task code with
  259.      *    the handle of our data structure so that the patch code has access to
  260.      *    the data.  The patch code assigns its data structure handle to 0x12345678
  261.      *    (which is a bogus address).  We use Munger to find this pattern
  262.      *    and replace it with the real address of our data structure handle.
  263.      */
  264.  
  265.         replaceWith = (long)( myData );
  266.         toReplace = 0x12345678;
  267.         
  268.         if ( stillOK && installPatch )
  269.             Munger( myTask, 0L, &toReplace, 4, &replaceWith, 4 );
  270.  
  271.     /*    The original code also used Munger to force the patch code to jump to
  272.      *    the original trap address after it executed.  I'm leaving that up to the
  273.      *    patch code to do by itself (if it wants to).  The original (old) trap
  274.      *    address is stored in the oldTrap field in the shared data structure.
  275.      *    
  276.      *    Now we actually patch the trap.  We've waited until now to detach and
  277.      *    lock the task (patch) code because Munger expects a movable/resizeable
  278.      *    Handle.
  279.      */
  280.         if ( stillOK && installPatch )
  281.         {
  282.             DetachResource( myTask );
  283.             HLock( myTask );
  284.         
  285.             myTaskAddr = (long)(StripAddress( (Ptr)(*myTask) ) );
  286.             NSetTrapAddress( myTaskAddr, kTrapToPatch, ToolTrap );
  287.             
  288.             myData->patched = true;
  289.         }
  290.         else
  291.         {
  292.             myData->patched = false;
  293.         }
  294.     
  295.     /*    Store the address of our shared data structure in a resource that
  296.      *    can be accessed by our control panel.  That way, the control panel 
  297.      *    can use and change our shared data.
  298.      */
  299.         if ( stillOK )
  300.         {
  301.             addrHandle = (memAddrHdl)Get1Resource( kMemAddrType, kMemAddrID );
  302.             if ( addrHandle )    /* got the resource */
  303.             {
  304.                 (*addrHandle)->theAddr = replaceWith;    /* store value of myData */
  305.                 ChangedResource( (Handle)addrHandle );
  306.                 WriteResource( (Handle)addrHandle );    /* write rsrc back to file */
  307.             }
  308.             else    /* create a new resource */
  309.             {
  310.                 addrHandle = (memAddrHdl)NewHandleClear( sizeof( long ) );
  311.                 if ( addrHandle )
  312.                 {
  313.                     (*addrHandle)->theAddr = replaceWith;    /* store value of myData */
  314.                     AddResource( (Handle)addrHandle, kMemAddrType, kMemAddrID,
  315.                         "\pShared Memory Addr" );        /* add a rsrc to file */
  316.                     WriteResource( (Handle)addrHandle ); /* write it out to the file */
  317.                 }
  318.                 else
  319.                 {
  320.                     stillOK = false;    /* unable to allocate memory for new rsrc */
  321.                 }
  322.             }
  323.         }
  324.         
  325.     /*    If there was a problem and it looks like the trap was still patched,
  326.      *    go ahead and remove the patch (restoring the original trap address).
  327.      */
  328.      
  329.          if ( ( !stillOK ) && sharedDataOK )
  330.          {
  331.              if ( myTask )    /* if the task code was loaded, it was probably installed */
  332.              {
  333.                  NSetTrapAddress( (long)StripAddress( (Ptr)(myData->oldTrap) ),
  334.                      kTrapToPatch, ToolTrap );
  335.                  DisposeHandle( myTask );
  336.                  myTask = NULL;
  337.                  
  338.                  myData->patched = false;
  339.              }
  340.          }
  341.     
  342.     /*    Show our icon in the startup icon parade.  If there was a problem somewhere
  343.      *    along the way, we'll show the icon even if the control panel says not to.
  344.      */
  345.  
  346.         if ( showStartupIcon || ( !stillOK ) )
  347.         {
  348.             if ( stillOK )
  349.                 if ( installPatch )
  350.                     ShowIconFamily( kIconFamilyID );
  351.                 else
  352.                     ShowIconFamily( kNoPatchIconID );
  353.             else
  354.                 ShowIconFamily( kXIconID );
  355.         }
  356.  
  357.     /*    Restore the memory zone to what it was when we began. */
  358.     
  359.         SetZone( saveZone );
  360.     
  361.     /*    Mark the data structure as no longer in use - we're through with it. */
  362.     
  363.         if ( sharedDataOK )
  364.             myData->inUse = false;
  365. }
  366.  
  367. #include "ShowIconFamily.c"
  368.